package com.dayatang.hrm.compensation.domain;

import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.util.Assert;

import com.dayatang.commons.domain.AbstractEntity;
import com.dayatang.commons.domain.InstanceFactory;
import com.dayatang.hrm.compensation.context.CompensationMessageSource;
import com.dayatang.hrm.compensation.domain.exception.CompensationRuntimeException;
import com.dayatang.hrm.compensation.utils.DateVersionUtils;
import com.dayatang.hrm.staffing.domain.Employee;

/**
 * 会计期间
 * 
 * 注意 inUse 字段用来标识该会计期间是否被使用，主要用来判别被使用的会计期间，是不能被删除等操作的 在处理会
 * 
 * 计期间时，要留意此标志位，记得赋值。
 * 
 * @author chencao
 * 
 */
@Entity
@Table(name = "pay_fiscal_period")
@NamedQueries( { @NamedQuery(name = "FiscalPeriod.findByFiscalYear", query = "select o from FiscalPeriod o inner join o.fiscalYear year where year = :pYear order by o.orderSeq") })
public class FiscalPeriod extends AbstractEntity {

	/**
	 * 
	 */
	private static final long serialVersionUID = 794043265150007798L;

	private static FiscalPeriodRepository fiscalPeriodRepository;

	protected static MessageSourceAccessor messages = CompensationMessageSource
			.getAccessor();

	@Column(name = "name")
	private String name;
	// 序号
	@Column(name = "order_seq", nullable = false)
	private Integer orderSeq;
	// 开始日期
	@Column(name = "begin_date")
	@Temporal(value = TemporalType.TIMESTAMP)
	private Date beginDate;
	// 结束日期
	@Column(name = "end_date")
	@Temporal(value = TemporalType.TIMESTAMP)
	private Date endDate;
	// 是否已经关闭
	@Column(name = "is_closed")
	private Boolean closed = false;
	// 操作人
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "operator_id")
	private Employee operator;
	// 最后操作日期
	@Column(name = "update_date")
	private Date updateDate;
	@ManyToOne
	@JoinColumn(name = "fiscal_year_id")
	private FiscalYear fiscalYear;

	public FiscalPeriod() {
	}

	public static MessageSourceAccessor getMessages() {
		return messages;
	}

	public static void setMessages(MessageSourceAccessor messages) {
		FiscalPeriod.messages = messages;
	}

	public static FiscalPeriodRepository getFiscalPeriodRepository() {
		if (fiscalPeriodRepository == null) {
			fiscalPeriodRepository = InstanceFactory
					.getInstance(FiscalPeriodRepository.class);
		}
		return fiscalPeriodRepository;
	}

	public static void setFiscalPeriodRepository(
			FiscalPeriodRepository fiscalPeriodRepository) {
		FiscalPeriod.fiscalPeriodRepository = fiscalPeriodRepository;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getOrderSeq() {
		return orderSeq;
	}

	public void setOrderSeq(Integer orderSeq) {
		this.orderSeq = orderSeq;
	}

	public Date getBeginDate() {
		return beginDate;
	}

	public void setBeginDate(Date beginDate) {
		this.beginDate = beginDate;
	}

	public Date getEndDate() {
		return endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	public Boolean isClosed() {
		return closed;
	}

	public Boolean getClosed() {
		return closed;
	}

	public void setClosed(Boolean closed) {
		this.closed = closed;
	}

	public Employee getOperator() {
		return operator;
	}

	public void setOperator(Employee operator) {
		this.operator = operator;
	}

	public Date getUpdateDate() {
		return updateDate;
	}

	public void setUpdateDate(Date updateDate) {
		this.updateDate = updateDate;
	}

	public FiscalYear getFiscalYear() {
		return fiscalYear;
	}

	public void setFiscalYear(FiscalYear fiscalYear) {
		if (isClosed()) {
			throw new CompensationRuntimeException(messages.getMessage(
					"FiscalPeriod.setSth.fiscalPeriodIsClosed", "该会计期间已经关闭。"));
		}
		this.fiscalYear = fiscalYear;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof FiscalPeriod == false) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		FiscalPeriod rhs = (FiscalPeriod) obj;
		return new EqualsBuilder().append(getId(), rhs.getId()).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder(17, 37).append(getId()).toHashCode();
	}

	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this,
				ToStringStyle.SHORT_PREFIX_STYLE);
	}

	/*
	 * =======================================
	 * 
	 * action
	 * 
	 * ========================================
	 */

	public void save() {
		validatePeriod();

		assembleOrderSeq();

		getFiscalPeriodRepository().save(this);
	}

	void assembleOrderSeq() {
		if (isNew()) {
			FiscalPeriod latestPeriod = getLatestPeriodByFiscalYear(fiscalYear);
			if (latestPeriod == null) {
				setOrderSeq(1);
			} else {
				setOrderSeq(latestPeriod.getOrderSeq() + 1);
			}
		}
	}

	public void remove() {
		getFiscalPeriodRepository().remove(this);
	}

	public void close() {
		setClosed(true);
		save();
	}

	public void validatePeriod() {
		Assert.notNull(beginDate, messages.getMessage(
				"FiscalPeriod.validatePeriod.beginDateIsNull",
				"会计期间的起始时间不允许为空。"));
		Assert
				.notNull(endDate, messages.getMessage(
						"FiscalPeriod.validatePeriod.endDateIsNull",
						"会计期间的结束时间不允许为空。"));

		if (!isPeriodValid()) {
			throw new CompensationRuntimeException(messages.getMessage(
					"FiscalPeriod.validatePeriod.periodNotValid", "该会计期间不合法。"));
		}
	}

	public boolean isPeriodValid() {

		FiscalPeriod latestPeriod = getLatestPeriodByFiscalYear(fiscalYear);

		if (latestPeriod == null) {
			// 第一个会计期间开始时间要求为年度的第一天的00:00:00
			String beginDateStr = DateFormatUtils.format(beginDate,
					"yyyy-MM-dd HH:mm:ss");
			String validBeginDateStr = fiscalYear.getYear() + "-01-01 00:00:00";

			// 结束时间末尾为23:59:59
			String endDateStr = DateFormatUtils.format(endDate,
					"yyyy-MM-dd HH:mm:ss");

			return (beginDateStr.equals(validBeginDateStr) && endDateStr
					.endsWith("23:59:59"));
		} else {
			// 要求开始日期 为最近一次会计期间结束日期第二天的开始00:00:00
			Date nextDay = DateVersionUtils.getNextDay(latestPeriod
					.getEndDate());

			String beginDateStr = DateFormatUtils.format(beginDate,
					"yyyy-MM-dd HH:mm:ss");
			String validBeginDateStr = DateFormatUtils.format(nextDay,
					"yyyy-MM-dd")
					+ " 00:00:00";

			// 结束时间末尾为23:59:59
			String endDateStr = DateFormatUtils.format(endDate,
					"yyyy-MM-dd HH:mm:ss");

			return (beginDateStr.equals(validBeginDateStr) && endDateStr
					.endsWith("23:59:59"));
		}

	}

	public static FiscalPeriod get(Long id) {
		return getFiscalPeriodRepository().get(id);
	}

	public static List<FiscalPeriod> findByFiscalYear(FiscalYear fiscalYear) {
		return getFiscalPeriodRepository().findByFiscalYear(fiscalYear);
	}

	public static FiscalPeriod getLatestPeriodByFiscalYear(FiscalYear fiscalYear) {
		return getFiscalPeriodRepository().getLatestPeriodByFiscalYear(
				fiscalYear);
	}
}
